package com.arcaneshift.servlet.abstracts;

import java.util.Calendar;
import java.util.List;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import com.arcaneshift.model.abstracts.AbstractCard;
import com.arcaneshift.model.action.game.Player;
import com.arcaneshift.model.util.RoundPhase;
import com.arcaneshift.servlet.util.network.HTTPProtocol;
import com.arcaneshift.servlet.util.network.RequestAction;
import com.common.model.abstracts.AbstractRequest;
import com.common.model.interfaces.IRequestAction;
import com.common.model.util.UserType;
import com.common.security.errors.ParserError;
import com.common.security.exceptions.HTTPException;
import com.common.security.exceptions.ParserException;
import com.common.servlet.abstracts.AbstractXMLParser;

/**
 * The XMLParser converts all the XML files provided in their appropriate Request class. 
 * It can throw many exceptions and it's the servlet's job to interpretate and respond
 * with the apropriate message. The messages for the exceptions that the parser can
 * throw can be found in the ParserError.
 * 
 * @author Ady
 *
 */
public abstract class XMLParserBase extends AbstractXMLParser {

	protected ParserError error;
	
	protected void insertAction(Node actionNode, AbstractRequest request) throws ParserException, HTTPException {
		if (actionNode.getNodeType() == Node.ELEMENT_NODE) {
			Element element = (Element) actionNode;
			IRequestAction action = RequestAction.contains(element.getAttribute(HTTPProtocol.ATTRIBUTE_NAME));
			
			if (action == null) {
				throw new HTTPException(HTTPException.ACTION_NOT_AVAILABLE);
			}
			request.setAction(action);
		} else {
			throw new ParserException(ParserException.CONTENT_BAD_FORMAT);
		}
	}
	
	/**
	 * Get the action tag that should be in the main Node before the content tag. It is the
	 * only current tag that has name attribute instead of value.
	 * <Action name="" />
	 * 
	 * @param action
	 * @return
	 */
	protected String getAction(IRequestAction action) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.ACTION_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.NAME_ATTRIBUTE);
		builder.append(escapeXML(action.toString()));
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the session tag that should be in the Content tag. The sessionId provided is the
	 * id of the session as value.
	 * <Session value="" />
	 * 
	 * @param sessionId
	 * @return
	 */
	protected String getSessionId(String sessionId) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.SESSION_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(sessionId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the game tag that should be in the Content tag. The gameId provided is the id of
	 * the game as value and the playerNumber is the the player order.
	 * <Game value="" player="" />
	 * 
	 * @param gameId, playerNumber
	 * @return
	 */
	protected String getGame(String gameId, int playerNumber) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.GAME_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(gameId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.PLAYER_ATTRIBUTE);
		builder.append(playerNumber);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the channel tag that should be in the Content tag. The token provided is
	 * the id of the channel as value.
	 * <Channel value="" />
	 * 
	 * @param token
	 * @return
	 */
	protected String getChannel(String token) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.CHANNEL_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(token);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the game tag that should be in the Content tag. The gameId provided is the id of
	 * the game as value.
	 * <Game value="" />
	 * 
	 * @param gameId
	 * @return
	 */
	protected String getGameId(String gameId) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.GAME_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(gameId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the session tag block as it can be provided by the Session model.
	 * <Session value="" userId="" userType="" />
	 * 
	 * @param sessionId
	 * @param userId
	 * @param userType
	 * @return
	 */
	protected String getSession(String sessionId, Long userId, UserType userType) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.SESSION_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(sessionId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.USER_ID_ATTRIBUTE);
		builder.append(userId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.USER_TYPE_ATTRIBUTE);
		builder.append(userType);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the queue player tag block as it can be provided by the QueuePlayer model.
	 * <QueuePlayer value="" sessionId="" time="" />
	 * 
	 * @param userId
	 * @param sessionId
	 * @return
	 */
	protected String getQueuePlayer(Long userId, String sessionId, Calendar time) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.QUEUE_PLAYER_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(userId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.SESSION_ID_ATTRIBUTE);
		builder.append(sessionId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.TIME_ATTRIBUTE);
		builder.append(time.getTime());
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the game tag block as it can be provided by the BattleEngine model.
	 * <Game value="" player="" player="" />
	 * 
	 * @param gameId
	 * @return
	 */
	protected String getBattleEngine(String gameId, List<Player> players) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.GAME_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(gameId);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		
		for (Player player : players) {
			builder.append(HTTPProtocol.SPACE);
			builder.append(HTTPProtocol.PLAYER_ATTRIBUTE);
			builder.append(player.getSession().getId());
			builder.append(HTTPProtocol.END_ATTRIBUTE);
		}
		
		builder.append(HTTPProtocol.END_TAG);
		
		
		
		return builder.toString();
	}
	
	/**
	 * Get a matrix block as it is provided by a List of Lists of Items.
	 * 
	 * @param matrix
	 * @return
	 */
	protected <T> String getGameMatrix(List<List<T>> matrix) {
		StringBuilder builder = new StringBuilder();
		
		for (int i = 0; i < matrix.size(); i++) {
			builder.append(HTTPProtocol.COLUMN_TAG);
			builder.append(HTTPProtocol.END_LINE);
			
			for (int j = 0; j < matrix.get(i).size(); j++) {
				builder.append(HTTPProtocol.SQUARE_TAG);
				builder.append(HTTPProtocol.SPACE);
				builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
				builder.append(eval(matrix.get(i).get(j)));
				builder.append(HTTPProtocol.END_ATTRIBUTE);
				builder.append(HTTPProtocol.END_TAG);
				builder.append(HTTPProtocol.END_LINE);
			}
			
			builder.append(HTTPProtocol.COLUMN_END_TAG);
			builder.append(HTTPProtocol.END_LINE);
		}
		
		return builder.toString();
	}
	
	/**
	 * Get the hand of the player as it is provided by a list of objects.
	 * <Hand player="1" size="2">
	 * 		<Card type="Spell" name="Fire Nova" />
	 * 		<Card type="Spell" name="Fire Nova" />
	 * </Hand>
	 * 
	 * @return
	 */
	protected String getHand(List<AbstractCard> cards, int player) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.HAND_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.PLAYER_ATTRIBUTE);
		builder.append(player);
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.SIZE_ATTRIBUTE);
		builder.append(cards.size());
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.CLOSE_TAG);
		
		for (int i = 0; i < cards.size(); i++) {
			builder.append(HTTPProtocol.END_LINE);
			builder.append(getCard(cards.get(i)));
		}
		
		builder.append(HTTPProtocol.HAND_END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the card as it is provided.
	 * 
	 * <Card type="CREATURE" name="Crimson Witch" />
	 * 
	 * @return
	 */
	protected String getCard(AbstractCard card) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.CARD_TAG);
		if (card != null) {
			builder.append(HTTPProtocol.SPACE);
			builder.append(HTTPProtocol.TYPE_ATTRIBUTE);
			builder.append(card.getType().toString());
			builder.append(HTTPProtocol.END_ATTRIBUTE);
			builder.append(HTTPProtocol.SPACE);
			builder.append(HTTPProtocol.NAME_ATTRIBUTE);
			builder.append(card.getName());
			builder.append(HTTPProtocol.END_ATTRIBUTE);
		}
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
	
	/**
	 * Get the phase as it is provided.
	 * 
	 * <Phase value="DRAW" />
	 * 
	 * @return
	 */
	protected String getPhase(RoundPhase phase) {
		StringBuilder builder = new StringBuilder();
		
		builder.append(HTTPProtocol.PHASE_TAG);
		builder.append(HTTPProtocol.SPACE);
		builder.append(HTTPProtocol.VALUE_ATTRIBUTE);
		builder.append(phase.toString());
		builder.append(HTTPProtocol.END_ATTRIBUTE);
		builder.append(HTTPProtocol.END_TAG);
		
		return builder.toString();
	}
}
